﻿#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//下⾯编译为32位（x86）程序的运⾏结果是什么（）
//A.编译报错 B.运⾏报错 C. 8 D. 12
class Base
{
public:
	
	virtual void Func1()
	{
		cout << "Func1()" << endl;
	}
	virtual void Func2()
	{
		cout << "Func2()" << endl;
	}

protected:
	int _b = 1;
	char _ch = 'x';
};


class Person {
public:
	//编译器还会在每个含有虚函数的类的对象中插入一个隐藏的指针
	//成员函数加上virtual后Base就会存在一个虚函数表指针_vfptr
	//它指向一个虚函数表（本质是一个数组，存的是指向类内虚函数的指针）
	virtual void BuyTicket() { cout << "买票-全价" << endl; }
	virtual void Print() { ; }
protected:
	string _name;
};
class Student : public Person {
public:

	//通过调试可以发现：如果子类未重写父类的虚函数，那么子类的vfptr（子类的vfptr
	// 不等于父类的vfptr）指向的虚函数表里存的仍然是父类的虚函数的地址。
	// 如果派⽣类中重写的基类的虚函数，派⽣类的虚函数表中对应的虚函数就会被覆盖成
	// 派⽣类重写的虚函数地址（这也是重写也可以叫做覆盖
	// 的原因）。
	// 
	// 注意：派⽣类的虚函数表中包含，基类中未被重写的虚函数地址，派⽣类重写父类的虚函数的地址，
	// 派⽣类⾃⼰的虚函数地址三个部分。
	// 
	// 因此，如果子类未重写虚函数，而下面func()的ptr调用的是父类的虚函数

	virtual void BuyTicket(){ cout << "买票-打折" << endl; }
	virtual void Print() { ; }
protected:
	string _id;
};
class Soldier : public Person {
public:
	/*virtual void BuyTicket() { cout << "买票-优先" << endl; }*/
protected:
	string _rank;
};
void Func(Person* ptr)
{
	// 虽然都是Person指针ptr在调⽤BuyTicket
    // 但是跟ptr没关系，⽽是由ptr指向的对象决定的。
	//在运行时，ptr根据自己指向的对象（可能父类可能子类），
	// 找到该对象内的虚函数指针vfptr（取该对象的前四个字节或八个字节（64位）就能找到vfptr）
	//然后根据该指针找到对应的虚函数表（即函数指针数组），在该表（数组）中找到BuyTicket()
	//这个函数。

	ptr->BuyTicket();
}

void test1() {
	Base b;
	cout << sizeof(b) << endl; //12

}
void test2()
{
	Person person;
	Student student;
	Soldier soldier;
	Func(&person);
	Func(&student);
	Func(&soldier);
}

void test3() {

	//相同类的对象它们共用一个虚函数表 ,它们的vfptr也是一样的（可以调试发现）
	// 
	// 虚函数的地址不直接存放在对象内的原因也是为了相同类对象共用一个虚函数表。
	//而不同类的对象的虚函数表是不一样的。

	Person p1;
	Person p2;
	Person p3;

}

int main()
{
	test2();
	
}


//问题:虚函数存在哪的？
// 虚函数和普通函数⼀样的，编译好后是⼀段指令，都是存在代码段的，只是虚函
// 数的地址⼜存到了虚表中。

//问题：虚函数表存在哪的？
// 这个问题严格说并没有标准答案C++标准并没有规定，下⾯的代码可以
//对⽐验证⼀下。vs下是存在代码段(常量区)


//class Base {
//public:
//	virtual void func1() { cout << "Base::func1" << endl; }
//	virtual void func2() { cout << "Base::func2" << endl; }
//	void func5() { cout << "Base::func5" << endl; }
//protected:
//	int a = 1;
//};
//class Derive : public Base
//{
//public:
//	// 重写基类的func1
//	virtual void func1() { cout << "Derive::func1" << endl; }
//	virtual void func3() { cout << "Derive::func1" << endl; }
//	void func4() { cout << "Derive::func4" << endl; }
//protected:
//	int b = 2;
//};
//int main()
//{
//	Base b;
//	Derive d;
//	return 0;
//}
//int main()
//{
//	int i = 0;
//	static int j = 1;
//	int* p1 = new int;
//	const char* p2 = "xxxxxxxx";
//	printf("栈:%p\n", &i);
//	printf("静态区:%p\n", &j);
//	printf("堆:%p\n", p1);
//	printf("常量区:%p\n", p2);
//	Base b;
//	Derive d;
//	Base* p3 = &b;
//	Derive* p4 = &d;
//	printf("Person虚表地址:%p\n", *(int*)p3); //*(int*)p3可以取出vfptr
//	printf("Student虚表地址:%p\n", *(int*)p4);
//	printf("虚函数地址:%p\n", &Base::func1);
//	printf("普通函数地址:%p\n", &Base::func5);
//	return 0;
//}
